#include "io.h"
#include "hop_sort.h"
#include "sortcg.h"

/*
 * Serazuje tak, ze nejprve nacte src a dest do pameti. Ulozi src na 
 * misto dest a z dest udela src. Dale v cyklu se jiz nacita jen dest a
 * src se stava z dest.
 * 
 * Rozdil mezi hop_sort a triple_sort je hlavne ten, ze blok v dest 
 * bude vzdy premazan src blokem. Proto pokud pouzivam mmap, musi 
 * se bloky prekopirovat do extra bufferu.
 */
int
hop_sort(GLBVAL *glb, int spos) 
{
	int			bufsrc[MAXBSIZE];
	int			bufdest[MAXBSIZE];
	int 		ret;
		
	uint		blksrc;
	uint		blkdest;
	char		*buf_src;
	char		st_buf[2][MAXBSIZE];
	uint8_t		indx_src;
	uint8_t		indx_dest;
	
	char		*buf_dest;		
	struct ufs1_dinode	*dp;	
	
	SWPDATA 	*swpsrc;
	SWPDATA 	*swpdest;
	SWPDATA 	*swptmp;
	BLOCKARRS 	*aptmp;
	BLOCKARRS 	*apcurr;
	BLOCKARRS	**blockap;
	
	blockap = (BLOCKARRS**)glb->blockap;
	
	swpsrc = (SWPDATA *) malloc (sizeof(SWPDATA));
	swpdest = (SWPDATA *) malloc (sizeof(SWPDATA));
	if (swpsrc == NULL || swpdest == NULL) {
		warn("Malloc error in sort");
		return 1;
	}
	
	indx_src = 0;
	indx_dest = 1;
	
	
	/*
	 * SRC
	 */
	bzero (swpsrc, sizeof(SWPDATA));
	swpsrc->buf = (void *) bufsrc;
	prepare_swp_src (glb, swpsrc, spos);
		
	/* adresa */
	if (swpsrc->flags & SWPDB) {
		dp = &(((struct ufs1_dinode *) swpsrc->buf)[ino_to_fsbo(&afs, swpsrc->ino)]);
		blksrc = dp->di_db[swpsrc->blkindx];
	}
	else {
		blksrc = ((int *)(swpsrc->buf))[swpsrc->blkindx];
	}	
	
	/* read */
	buf_src = st_buf[indx_src];
	if (read_fs_block(glb, (void **) &buf_src, blksrc)) {
		fprintf(stderr, "Error in hop sort\n");
		return 1;
	}
	
	/* bitmapa - nevim jestli neco prijde na toto misto, tak uvolnim*/	
	cgbitmap_set(glb, blksrc);
				
	/* odeberu z blockap */
	apcurr = blockap[swpsrc->apindx];
	blockap[swpsrc->apindx] = NULL;

	do {
		/*
		 * DEST
		 */
		bzero (swpdest, sizeof(SWPDATA));
		bind_swpdata_mem(swpsrc, swpdest, bufsrc, bufdest);
		ret = prepare_swp_dest (glb, swpsrc, swpdest, apcurr);
		if (ret) {
			fprintf(stderr, "Error in hop sort\n");
			return 1;
		}
					
		/* dest adr, nedelam pokud je free, free v blockap muze byt NULL */
		if (swpdest->flags != ZERODESTINO) {
			if (swpdest->flags & SWPDB) {
				dp = &(((struct ufs1_dinode *) swpdest->buf)[ino_to_fsbo(&afs, swpdest->ino)]);
				blkdest = dp->di_db[swpdest->blkindx];
			}
			else {
				blkdest = ((int *)(swpdest->buf))[swpdest->blkindx];
			}	
		}
		/* cil je prazdny, musim vypocitat adresu */
		else {
			blkdest = indxtoblk(glb, swpdest->apindx);
		}
		
		/* dest read */
		if (swpdest->flags != ZERODESTINO) {
			buf_dest = st_buf[indx_dest];
			if (read_fs_block(glb, (void **) &buf_dest, blkdest)) {
				fprintf(stderr, "Error in hop sort\n");
				return 1;
			}
		
		
			/* 
			 * v pripade mmap jsem zacal ukazovat do oblasti, ale 
			 * v dalsim kroku bych si blok smazal
			 * musim prekopirovat
			 */
			if (buf_dest != st_buf[indx_dest]) {
				memcpy(st_buf[indx_dest], buf_dest, afs.fs_bsize);
				buf_dest = st_buf[indx_dest];
			}
		}
		
		
		/*
		 * PRESUN BLOKU
		 */
		/* src write*/
		if (write_fs_block(glb, buf_src, blkdest)) {
			fprintf(stderr, "Error in hop sort\n");
			return 1;
		}


		/* 
		 * INODY 
		 */
		ret = swap_inode(glb, swpsrc, blkdest);		
		if (ret == SWAP_ERR) {
			fprintf(stderr, "Error in hop sort\n");
			return 1;
		}
		
		/* 
		 * BLOCKAP 
		 */
		aptmp = blockap[swpdest->apindx];
		blockap[swpdest->apindx] = apcurr;
		blockap[swpdest->apindx]->apindx = swpdest->apindx;
		apcurr = aptmp;		
		
		
		/*
		 * SWAP DEST->SRC
		 */
		swptmp = swpsrc;
		swpsrc = swpdest;
		swpdest = swptmp;
		
		indx_src = (indx_src + 1) % 2;
		indx_dest = (indx_dest + 1) % 2;
		buf_src = st_buf[indx_src];
		

		
	} while (swpsrc->flags != ZERODESTINO); /* swpdest -> swpsrc */
	
	/* bitmapa - musel byt vlozen na neobsazenou pozici */
	cgbitmap_clr(glb, blkdest);
	
	/* neukladam cg (bitmapu) po kazde zmene, fsck ji umi opravit */
	if (write_cgblock(glb) == 1)
		return 1;		
	
	free(swpsrc);
	free(swpdest);

	return 0;
}

